window.onload VS window.document.onload

2016.08.01

window.onload

一般来说,window.onload 会在整个页面加载完成后触发,包括图片,css,以及依赖库等等

在一些(不是全部)浏览器中,也会在 dom tree 加载完成后触发

document.onload

在 dom tree 加载完成后触发,一般早于图片,css,以及依赖库的加载

小坑

一般比较习惯用 document.onload,但是今早为一个div绑定事件,却发现使用 document.onload 怎么也触发不了事件,按理说DOM元素存在就可以正常出发,但这个问题一直困扰了我很久,所以才决定搞清楚确保元素加载的顺序。

折腾了一大圈,才发现问题的所在是因为我要绑定的div其实是一个空盒子,是一个由CSS去添加样式写成的图标

<div id="icon"></div>

这样的空div虽然 DOM Node 存在了,但是由于css尚未加载进来,实际在页面上是一个空节点,这时候即便用getElementByID去获取节点,也是一个空白节点(不是null),而不是你想要的那个div图标。

window的其他属性可以参见window属性列表

Javascript 区分传递函数和执行函数

2016.08.01

JS事件绑定很常见,但是遇到了一个奇怪的事情,如下:

document.getElementById("b1").onclick = changePage(page1, page2);

function changePage(removePage, addPage){
  removePage.classList.remove("pt-page-current");
  addPage.classList.add("pt-page-current");
}

正常情况下,onclick事件绑定后,应该只有在单击事件发生后,才会执行changePage,但是实际情况显示,在页面加载onload 完成后,changePage(page1, page2) 已经被触发了一次…

测试下哪里不对,所以换一种方法

document.getElementById("b1").onclick = function(){
  page1.classList.remove("pt-page-current");
  page2.classList.add("pt-page-current");
}

成功运行… 可是为什么呢?以前写的页面貌似也在onclick后面调用过函数啊,并不记得有这样诡异的问题… 更何况如果不能包在一个函数里,那么就会出现大量的冗余js代码,不利于维护也实在是丑… 再实验

document.getElementById("b1").onclick = test;
function test(){
  console.log("test"};
}	//结果正常,只有在单击button的情况下才会输出 test
              
document.getElementById("b1").onclick = test(123);
function test(e){
  console.log("test" + e);
}	//结果异常,页面加载结束后就会自动输出 test123

心里隐隐觉得这肯定是javascript某种鬼机制… 查文档发现原来是自己没有搞清楚Javascript里传递函数和执行函数的区别,写在这里记录一下

function myFunc() {...};
$("selector").on("click", myFunc);    // "myFunc" is the handler,we pass a function here

function myFunc() {...};
$("selector").on("click", myFunc());  // execute "myFunc" -- its return value is the handler

当我们在传递js函数时,要谨记:

不带括号的函数意味着把函数传递给事件handler,事件触发==>启动函数

带括号的函数意味着我们先执行了函数,并且把函数执行的结果传递给了事件,事件触发==>null

所以上面写下 document.getElementById("b1").onclick = changePage(page1, page2); 这句代码的时候,实际上changePage(page1, page2)已经被执行了,并且我们的onclick事件等于的是一个null(没有返回值),所以我们能看见的结果就是绑定的函数在页面加载完成后就已经被执行,并且click操作没有效果。相反,如果使用 onclick = function(){…} ,就不会有自动执行的问题。

但是,如果像上面的例子,函数是带参数的时候,我们不能避免要用到括号,有两种方式可以解决问题:

// 1. 把函数包在一个anonymous function里
document.getElementById("b1").onclick = function(){changePage(page1, page2);};

// 2. 多次调用的时候,可以创建一个辅助函数
function createHandler(page1, page2) {
    return function() { changePage(page1, page2); };
}
document.getElementById("b1").onclick = createHandler(page1, page2);
document.getElementById("b2").onclick = createHandler(page1, page2);
document.getElementById("b3").onclick = createHandler(page1, page2);

Document.getElementByClassName 返回值

2016.08.02

在对一组DOM元素进行遍历的时候遇到了这个问题:

domArr = document.getElementByClassName("test");
domArr.forEach(function(e){
  console.log(e);
})
//返回error:domArr.forEach is not a function

在浏览器里调试,domArr 返回的是一组dom 元素,可以用 domArr[i] 来调用各个DOM元素

array.forEach(function(){…}) 一样没有错

原因在于document.getElementByClassName 返回的是List (HTMLCollection or NodeList),它们并不是Array,所以不能使用Array的foreach方法

解决方案

  1. 使用传统for循环

  2. 使用Array转化

    Array.prototype.forEach.call(domArr, function (e) {...});

    OR

    Array.from(domArr).forEach(function(e){…})

  3. [推荐] document.querySelectorAll(".test")

    document.querySelectorAll 返回的就是一个真正的Array

注意:forEach, every, querySeletorAll 等等属于ES5+ 内容,IE10以下浏览器也许不兼容,需要polyfill等

Jumbotron 全屏视频

现在很流行Jumbotron 背景是动态的视频,然而视频不能像图片一样作为背景,配合使用background-sizebackground-position 达到相应式的目的,所以记录下两种解决办法:

Solution1: Object-fit

新方法, object-fit: cover 能够达到 background-size: cover 一样的效果,而且可以直接作用在html5 video tag 上

  • 缺点:不兼容IE

Solition2: IE Hack

& video {
  min-height: 100%;
  min-width: 100%;
  height: auto;
}